import Taro from '@tarojs/taro'
/**
 * 缓存管理器
 */
export default class CacheManager {
    static CACHE_PAGE_SIZE: number = 3

    cacheListener: CacheListener
    useCache: boolean = true
    allAbort: boolean = false
    page: number
    total: number
    index: number
    pages: Array<Array<string>> = []
    tasks: Map<string, any> = new Map<string, any>()
    caches: Map<string, string> = new Map<string, string>()

    constructor(data: string[], cacheListener: CacheListener) {
        this.cacheListener = cacheListener
        this.pages = chunking(data, CacheManager.CACHE_PAGE_SIZE)
        this.index = 0
        this.page = 0
        this.total = this.pages.length
    }

    load = (page: number) => {
        if (this.useCache) {
            const isLoad: boolean = (page === 0) ? true : (page / CacheManager.CACHE_PAGE_SIZE) > this.page
            if (this.total > 0 && isLoad) {
                if (this.page < this.total) {
                    const items = this.pages[this.page]
                    const all: Promise<SaveResult>[] = items.map((item) => {
                        return this.download(item)
                    })
                    Promise.all(all).then((values) => {
                        values.forEach((value) => {
                            this.caches.set(value.key, value.path)
                        })
                    }).catch((reason) => {
                        console.log('缓存创建异常:', reason)
                    })
                    this.page++
                }
            }
        } else {
            this.index = CacheManager.CACHE_PAGE_SIZE
            this.page = this.total
            this.onItemComplete()
        }
    }

    download = (url: string): Promise<SaveResult> => {
        return new Promise<SaveResult>((resolve, reject) => {
            const key = this.genKey(url)
            const task = Taro.downloadFile({
                url, header: { Accept: 'image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5' }
            })
            this.tasks.set(url, task)
            task.then((res: Taro.downloadFile.Promised) => {
                Taro.saveFile({
                    tempFilePath: res.tempFilePath
                }).then((res: Taro.saveFile.Promised) => {
                    resolve({ key, src: url, path: res.savedFilePath })
                }).catch((reason) => reject(reason))
                this.onItemComplete()
            }).catch((reason) => {
                this.onItemComplete()
                reject(reason)
            });
            (task as any).progress((e: any) => {
                if (this.allAbort) {
                    this.tasks.get(url).abort()
                    this.tasks.delete(url)
                } else if (e.process === 100) {
                    this.tasks.get(url).abort()
                    this.tasks.delete(url)
                }
            })
        })
    }

    onItemComplete = () => {
        let progress: number
        if (this.index < CacheManager.CACHE_PAGE_SIZE) {
            progress = (++this.index) / CacheManager.CACHE_PAGE_SIZE * 100
        } else {
            // 一页缓存加载完毕
            this.index = 0
            progress = 100
        }
        this.cacheListener.onProgress(progress)
    }

    isComplete = () => {
        return !(this.page < this.total)
    }

    setUseCache = (useCache: boolean) => {
        this.useCache = useCache
    }

    getCacheUrl = (url: string) => {
        const key = this.genKey(url)
        const cacheUrl = this.caches.get(key)
        if (cacheUrl) {
            return cacheUrl
        }
        return url
    }

    genKey = (url: string) => {
        const key = url.replace(/\?\S*/g, '')
        return encodeURI(key)
    }

    clear = () => {
        if (this.caches && this.caches.size > 0) {
            for (let filePath of this.caches.values()) {
                Taro.removeSavedFile({
                    filePath
                }).then()
            }
            this.caches.clear()
        }
        Taro.getSavedFileList().then((infos) => {
            if ('getSavedFileList:ok' === infos.errMsg) {
                for (let i = 0; i < infos.fileList.length; i++) {
                    const file = infos.fileList[i]
                    Taro.removeSavedFile({
                        filePath: file.filePath
                    })
                }
            }
        })
    }

    destroy = () => {
        if (this.tasks && this.tasks.size > 0) {
            for (let key in this.tasks.keys) {
                const task = this.tasks.get(key)
                if (task) {
                    task.abort()
                }
                this.tasks.delete(key)
            }
        }
    }
}
interface SaveResult {
    key: string,
    src: string
    path: string
}

interface CacheListener {
    onProgress: (value: number) => void
}
/**
 * 页分块
 * @param arr 数据
 * @param size 块大小
 */
function chunking(arr: string[], size: number) {
    size = Math.max(size, 0)
    const len = arr == null ? 0 : arr.length // array如果不是null就取出length，否则length 为0
    if (!len || size < 1) {
        return [] // 不是array，就直接返回一个空数组。
    }
    const blocks = new Array(Math.ceil(len / size))// Math.ceil(10/3) = 4 result应该为4个长度的数组。
    let i = 0
    let j = 0
    while (i < len) {
        blocks[j++] = arr.slice(i, (i += size)) // while循环生成result的数组。
    }
    return blocks
}
